﻿namespace BassettData.Robots
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// The base Karel the Robot class. Inherit (or decorate) this class as necessary to 
    /// add desired behaviours.
    /// </summary>
    public class UrRobot
    {
        /// <summary>
        /// The count of beepers in the robot's bag.
        /// </summary>
        private int beeperCount;

        /// <summary>
        /// The current direction in which the robot is headed.
        /// </summary>
        private Direction currentDirection;

        /// <summary>
        /// If true, the robot is on.
        /// </summary>
        private bool isTurnedOn;

        /// <summary>
        /// Initializes a new instance of the <see cref="UrRobot"/> class.
        /// </summary>
        /// <param name="startAvenue">The start avenue.</param>
        /// <param name="startStreet">The start street.</param>
        /// <param name="startDirection">The start direction.</param>
        /// <param name="initialBeeperCount">The initial beeper count.</param>
        public UrRobot(
            int startAvenue = 1, 
            int startStreet = 1, 
            Direction startDirection = Direction.East, 
            int initialBeeperCount = 0)
        {
            this.Location = new Location(startAvenue, startStreet);
            this.isTurnedOn = true;
            this.currentDirection = startDirection;
            this.beeperCount = initialBeeperCount;
        }

        /// <summary>
        /// Gets the location.
        /// </summary>
        /// <value>The robot's location.</value>
        public virtual Location Location { get; private set; }

        /// <summary>
        /// Picks the beeper up from the current corner.
        /// </summary>
        public void PickBeeper()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Turns the robot off. After the robot is off, no more operations can be performed.
        /// </summary>
        /// <returns>A description of where the robot is located.</returns>
        public virtual string TurnOff()
        {
            isTurnedOn = false;
            return string.Format("Robot Karel is at {0}.", Location);
        }

        /// <summary>
        /// Moves the robot to the next corner in the Direction that it is headed.
        /// </summary>
        /// <exception cref="InvalidOperationException">Thrown if the robot is off, or the 
        /// robot would bump into a wall, or off the edge of the world.</exception>
        public virtual void Move()
        {
            CheckTurnedOn();
            Location nextLocation = GetNextLocation();

            if (!LocationIsValid(nextLocation))
            {
                throw new InvalidOperationException(string.Format("Cannot move from {0} in direction {1}.", Location, currentDirection.ToString()));
            }

            Location = nextLocation;
        }

        /// <summary>
        /// Turns the robot left.
        /// </summary>
        /// <exception cref="InvalidOperationException">Thrown if the robot is off.</exception>
        public virtual void TurnLeft()
        {
            CheckTurnedOn();
            currentDirection = Mover.GetDirectionToLeft(currentDirection);
        }

        /// <summary>
        /// Checks the robot is turned on.
        /// </summary>
        private void CheckTurnedOn()
        {
            if (!isTurnedOn)
            {
                throw new InvalidOperationException("Robot is not turned on.");
            }
        }

        /// <summary>
        /// Gets the next location.
        /// </summary>
        /// <returns>The next location; not checked for validity.</returns>
        private Location GetNextLocation()
        {
            return Mover.Move(currentDirection, Location);
        }

        /// <summary>
        /// Checks the next location is valid.
        /// </summary>
        /// <param name="location">The location to try.</param>
        /// <returns>True if valid, otherwise, false.</returns>
        private bool LocationIsValid(Location location)
        {
            // TODO this needs to validate the robot's location in the world.
            return location.Avenue >= 1 && location.Street >= 1;
        }
    }
}